﻿//    Copyright 2014 LuoZhihui
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//      http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

#region  导入名称空间

using System;
using System.Collections.Generic;
using System.Reflection;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;

#endregion

namespace LotteryEngine.Repository.NHibernate.SessionStorage
{
	public class NHSessionFactory : INHSessionFactory
	{
		private static ISessionFactory _sessionFactory;
		private static string _connectionString;
		private static readonly ISet<Assembly> _assembliesSet = new HashSet<Assembly>();
		private static string _dbType;
		private static bool _debug;


		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="dbtype">数据库类型 Oracle、MySql、Postgres、SqlServer</param>
		/// <param name="connectionString"></param>
		/// /// <param name="debug">调试开发模式</param>
		/// <param name="mapping"></param>
		public NHSessionFactory(string dbtype, string connectionString, bool debug, IEnumerable<string> mapping)
		{
			_dbType = dbtype;
			_connectionString = connectionString;
			_debug = debug;

			foreach (var assemblyName in mapping)
			{
				var assembly = Assembly.Load(assemblyName);

				if (_assembliesSet.Contains(assembly))
				{
					continue;
				}

				_assembliesSet.Add(assembly);
			}
		}


		private static IPersistenceConfigurer BuildConfigurer(Action<ConnectionStringBuilder> connStrBuilder)
		{
			var dbType = _dbType.ToUpper();

			switch (dbType)
			{
				case "ORACLEMGR":
					var oraMgrDbCfg = OracleManagedDataClientConfiguration
						.Oracle10
						.ConnectionString(connStrBuilder)
						.FormatSql();

					return _debug ? oraMgrDbCfg.ShowSql() : oraMgrDbCfg;

				case "ORACLE":
					var oraDbCfg = OracleDataClientConfiguration
						.Oracle10
						.ConnectionString(connStrBuilder)
						.FormatSql();

					return _debug ? oraDbCfg.ShowSql().FormatSql() : oraDbCfg;

				case "MYSQL":
					var mySqlDbCfg = MySQLConfiguration
						.Standard
						.ConnectionString(connStrBuilder)
						.FormatSql();

					return _debug ? mySqlDbCfg.ShowSql() : mySqlDbCfg;

				case "POSTGRES":
					var postgresDbCfg = PostgreSQLConfiguration
						.Standard
						.ConnectionString(connStrBuilder)
						.FormatSql();

					return _debug ? postgresDbCfg.ShowSql() : postgresDbCfg;

				case "SQLSERVER":
					var sqlServerDbCfg = MySQLConfiguration
						.Standard
						.ConnectionString(connStrBuilder)
						.FormatSql();

					return _debug ? sqlServerDbCfg.ShowSql() : sqlServerDbCfg;
				default:
					throw new NotImplementedException(string.Format("不支持的数据库类型{0}", dbType));
			}
		}

		/// <summary>
		///     创建会话工厂
		/// </summary>
		/// <returns></returns>
		private ISessionFactory CreateSessionFactory()
		{
			var sessionFactory = Fluently.Configure()
				.Database(BuildConfigurer(c => c.Is(_connectionString)))
				.Mappings(m =>
				{
					foreach (var assembly in _assembliesSet)
					{
						m.FluentMappings.AddFromAssembly(assembly);
					}
				})
				.BuildSessionFactory();


			return sessionFactory;
		}


		private ISessionFactory GetSessionFactory()
		{
			return _sessionFactory ?? (_sessionFactory = CreateSessionFactory());
		}

		private ISession GetNewSession()
		{
			return GetSessionFactory().OpenSession();
		}

		public ISession CurrentSession
		{
			get
			{
				var sessionStorageContainer = SessionStorageFactory.GetStorageContainer();
				var currentSession = sessionStorageContainer.GetCurrentSession();
				if (currentSession != null)
				{
					return currentSession;
				}

				currentSession = GetNewSession();
				sessionStorageContainer.Store(currentSession);

				return currentSession;
			}
		}
	}
}